use crate::elf::elf_enum::*;
use crate::elf::*;

use nom::number::streaming::{le_u8, le_u16, le_u32, le_u64, le_i32, le_i64};
use nom::{IResult};


pub const ELF32_EHDR_SIZE: usize = 0x34;
pub const ELF64_EHDR_SIZE: usize = 0x40;
pub const ELF32_PHDR_SIZE: usize = 0x20;
pub const ELF64_PHDR_SIZE: usize = 0x38;
pub const ELF32_SHDR_SIZE: usize = 0x28;
pub const ELF64_SHDR_SIZE: usize = 0x40;


#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf32_Ehdr {
    pub e_ident: [u8; EI_NIDENT as usize],
    pub e_type: Elf32_Half,
    pub e_machine: Elf32_Half,
    pub e_version: Elf32_Word,
    pub e_entry: Elf32_Addr,
    pub e_phoff: Elf32_Off,
    pub e_shoff: Elf32_Off,
    pub e_flags: Elf32_Word,
    pub e_ehsize: Elf32_Half,
    pub e_phentsize: Elf32_Half,
    pub e_phnum: Elf32_Half,
    pub e_shentsize: Elf32_Half,
    pub e_shnum: Elf32_Half,
    pub e_shstrndx: Elf32_Half,
}

fn take16(input: &[u8]) -> IResult<&[u8], [u8; EI_NIDENT as usize]> {
    let mut ret_array: [u8; EI_NIDENT as usize] = Default::default();
    ret_array.copy_from_slice(&input[0..16]);
    Ok((&input[16..], ret_array))
}

named!(pub parser_elf32_ehdr<Elf32_Ehdr>,
    do_parse!(
        e_ident:    take16    >>
        e_type:     le_u16    >>
        e_machine:  le_u16    >>
        e_version:  le_u32    >>
        e_entry:    le_u32   >>
        e_phoff:    le_u32    >>
        e_shoff:    le_u32    >>
        e_flags:    le_u32    >>
        e_ehsize:   le_u16    >>
        e_phentsize:le_u16    >>
        e_phnum:    le_u16    >>
        e_shentsize:le_u16    >>
        e_shnum:    le_u16    >>
        e_shstrndx: le_u16    >>
        (Elf32_Ehdr {
            e_ident,
            e_type,
            e_machine,
            e_version,
            e_entry,
            e_phoff,
            e_shoff,
            e_flags,
            e_ehsize,
            e_phentsize,
            e_phnum,
            e_shentsize,
            e_shnum,
            e_shstrndx,
        })
    )
);

impl Elf32_Ehdr {
        fn to_le_bytes(&self)-> [u8; ELF32_EHDR_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();

        ret_buffer.extend_from_slice(&self.e_ident);
        ret_buffer.extend_from_slice(&self.e_type.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_machine.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_version.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_entry.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_phoff.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_shoff.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_flags.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_ehsize.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_phentsize.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_phnum.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_shentsize.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_shnum.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_shstrndx.to_le_bytes());

        return vec_to_array::<u8, ELF32_EHDR_SIZE>(ret_buffer);
    }
}


#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf64_Ehdr {
    pub e_ident: [u8; EI_NIDENT as usize],
    pub e_type: Elf64_Half,
    pub e_machine: Elf64_Half,
    pub e_version: Elf64_Word,
    pub e_entry: Elf64_Addr,
    pub e_phoff: Elf64_Off,
    pub e_shoff: Elf64_Off,
    pub e_flags: Elf64_Word,
    pub e_ehsize: Elf64_Half,
    pub e_phentsize: Elf64_Half,
    pub e_phnum: Elf64_Half,
    pub e_shentsize: Elf64_Half,
    pub e_shnum: Elf64_Half,
    pub e_shstrndx: Elf64_Half,
}

named!(parser_elf64_ehdr<Elf64_Ehdr>,
    do_parse!(
        e_ident:    take16    >>
        e_type:     le_u16    >>
        e_machine:  le_u16    >>
        e_version:  le_u32    >>
        e_entry:    le_u64   >>
        e_phoff:    le_u64    >>
        e_shoff:    le_u64    >>
        e_flags:    le_u32    >>
        e_ehsize:   le_u16    >>
        e_phentsize:le_u16    >>
        e_phnum:    le_u16    >>
        e_shentsize:le_u16    >>
        e_shnum:    le_u16    >>
        e_shstrndx: le_u16    >>
        (Elf64_Ehdr {
            e_ident,
            e_type,
            e_machine,
            e_version,
            e_entry,
            e_phoff,
            e_shoff,
            e_flags,
            e_ehsize,
            e_phentsize,
            e_phnum,
            e_shentsize,
            e_shnum,
            e_shstrndx,
        })
    )
);

impl Elf64_Ehdr {
    fn to_le_bytes(&self)-> [u8; ELF64_EHDR_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();

        ret_buffer.extend_from_slice(&self.e_ident);
        ret_buffer.extend_from_slice(&self.e_type.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_machine.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_version.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_entry.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_phoff.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_shoff.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_flags.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_ehsize.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_phentsize.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_phnum.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_shentsize.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_shnum.to_le_bytes());
        ret_buffer.extend_from_slice(&self.e_shstrndx.to_le_bytes());

        return vec_to_array::<u8, ELF64_EHDR_SIZE>(ret_buffer);
    }
}


#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf32_Phdr {
    pub p_type: Elf32_Word,
    pub p_offset: Elf32_Off,
    pub p_vaddr: Elf32_Addr,
    pub p_paddr: Elf32_Addr,
    pub p_filesz: Elf32_Word,
    pub p_memsz: Elf32_Word,
    pub p_flags: Elf32_Word,
    pub p_align: Elf32_Word,
}

named!(pub parser_elf32_phdr<Elf32_Phdr>,
    do_parse!(
        p_type:     le_u32    >>
        p_offset:   le_u32    >>
        p_vaddr:    le_u32    >>
        p_paddr:    le_u32    >>
        p_filesz:   le_u32   >>
        p_memsz:    le_u32    >>
        p_flags:    le_u32    >>
        p_align:    le_u32    >>
        (Elf32_Phdr {
            p_type,
            p_offset,
            p_vaddr,
            p_paddr,
            p_filesz,
            p_memsz,
            p_flags,
            p_align,
        })
    )
);

impl Elf32_Phdr {
    fn to_le_bytes(&self)-> [u8; ELF32_PHDR_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.p_type.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_offset.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_vaddr.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_paddr.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_filesz.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_memsz.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_flags.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_align.to_le_bytes());
        return vec_to_array::<u8, ELF32_PHDR_SIZE>(ret_buffer);
    }
}



#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf64_Phdr {
    pub p_type: Elf64_Word,
    pub p_flags: Elf64_Word,
    pub p_offset: Elf64_Off,
    pub p_vaddr: Elf64_Addr,
    pub p_paddr: Elf64_Addr,
    pub p_filesz: Elf64_Xword,
    pub p_memsz: Elf64_Xword,
    pub p_align: Elf64_Xword,
}

named!(parser_elf64_phdr<Elf64_Phdr>,
    do_parse!(
        p_type:     le_u32    >>
        p_flags:    le_u32    >>
        p_offset:   le_u64    >>
        p_vaddr:    le_u64    >>
        p_paddr:    le_u64    >>
        p_filesz:   le_u64   >>
        p_memsz:    le_u64    >>
        p_align:    le_u64    >>
        (Elf64_Phdr {
            p_type,
            p_flags,
            p_offset,
            p_vaddr,
            p_paddr,
            p_filesz,
            p_memsz,
            p_align,
        })
    )
);

impl Elf64_Phdr {
    fn to_le_bytes(&self)-> [u8; ELF64_PHDR_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.p_type.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_flags.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_offset.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_vaddr.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_paddr.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_filesz.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_memsz.to_le_bytes());
        ret_buffer.extend_from_slice(&self.p_align.to_le_bytes());
        return vec_to_array::<u8, ELF64_PHDR_SIZE>(ret_buffer);
    }
}



#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf32_Shdr {
    pub sh_name: Elf32_Word,
    pub sh_type: Elf32_Word,
    pub sh_flags: Elf32_Word,
    pub sh_addr: Elf32_Addr,
    pub sh_offset: Elf32_Off,
    pub sh_size: Elf32_Word,
    pub sh_link: Elf32_Word,
    pub sh_info: Elf32_Word,
    pub sh_addralign: Elf32_Word,
    pub sh_entsize: Elf32_Word,
}

named!(parser_elf32_shdr<Elf32_Shdr>,
    do_parse!(
        sh_name:        le_u32    >>
        sh_type:        le_u32    >>
        sh_flags:       le_u32    >>
        sh_addr:        le_u32    >>
        sh_offset:      le_u32    >>
        sh_size:        le_u32   >>
        sh_link:        le_u32    >>
        sh_info:        le_u32    >>
        sh_addralign:   le_u32    >>
        sh_entsize:     le_u32    >>
        (Elf32_Shdr {
            sh_name,
            sh_type,
            sh_flags,
            sh_addr,
            sh_offset,
            sh_size,
            sh_link,
            sh_info,
            sh_addralign,
            sh_entsize,
        })
    )
);

impl Elf32_Shdr {
    fn to_le_bytes(&self)-> [u8; ELF32_SHDR_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.sh_name.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_type.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_flags.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_addr.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_offset.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_size.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_link.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_info.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_addralign.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_entsize.to_le_bytes());
        return vec_to_array::<u8, ELF32_SHDR_SIZE>(ret_buffer);
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf64_Shdr {
    pub sh_name: Elf64_Word,
    pub sh_type: Elf64_Word,
    pub sh_flags: Elf64_Xword,
    pub sh_addr: Elf64_Addr,
    pub sh_offset: Elf64_Off,
    pub sh_size: Elf64_Xword,
    pub sh_link: Elf64_Word,
    pub sh_info: Elf64_Word,
    pub sh_addralign: Elf64_Xword,
    pub sh_entsize: Elf64_Xword,
}

named!(parser_elf64_shdr<Elf64_Shdr>,
    do_parse!(
        sh_name:        le_u32    >>
        sh_type:        le_u32    >>
        sh_flags:       le_u64    >>
        sh_addr:        le_u64    >>
        sh_offset:      le_u64    >>
        sh_size:        le_u64   >>
        sh_link:        le_u32    >>
        sh_info:        le_u32    >>
        sh_addralign:   le_u64    >>
        sh_entsize:     le_u64    >>
        (Elf64_Shdr {
            sh_name,
            sh_type,
            sh_flags,
            sh_addr,
            sh_offset,
            sh_size,
            sh_link,
            sh_info,
            sh_addralign,
            sh_entsize,
        })
    )
);

impl Elf64_Shdr {
    fn to_le_bytes(&self)-> [u8; ELF64_SHDR_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.sh_name.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_type.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_flags.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_addr.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_offset.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_size.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_link.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_info.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_addralign.to_le_bytes());
        ret_buffer.extend_from_slice(&self.sh_entsize.to_le_bytes());
        return vec_to_array::<u8, ELF64_SHDR_SIZE>(ret_buffer);
    }
}



pub const ELF32_CHDR_SIZE: usize = 12;
pub const ELF64_CHDR_SIZE: usize = 24;

#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf32_Chdr {
    pub ch_type: Elf32_Word,
    pub ch_size: Elf32_Word,
    pub ch_addralign: Elf32_Word,
}

named!(pub parser_elf32_chdr<Elf32_Chdr>,
    do_parse!(
        ch_type:        le_u32    >>
        ch_size:        le_u32    >>
        ch_addralign:   le_u32    >>
        (Elf32_Chdr {
            ch_type,
            ch_size,
            ch_addralign,
        })
    )
);

impl Elf32_Chdr {
    fn to_le_bytes(&self)-> [u8; ELF32_CHDR_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.ch_type.to_le_bytes());
        ret_buffer.extend_from_slice(&self.ch_size.to_le_bytes());
        ret_buffer.extend_from_slice(&self.ch_addralign.to_le_bytes());
        return vec_to_array::<u8, ELF32_CHDR_SIZE>(ret_buffer);
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf64_Chdr {
    pub ch_type: Elf64_Word,
    pub ch_reserved: Elf64_Word,
    pub ch_size: Elf64_Xword,
    pub ch_addralign: Elf64_Xword,
}

named!(parser_elf64_chdr<Elf64_Chdr>,
    do_parse!(
        ch_type:        le_u32    >>
        ch_reserved:    le_u32    >>
        ch_size:        le_u64    >>
        ch_addralign:   le_u64    >>
        (Elf64_Chdr {
            ch_type,
            ch_reserved,
            ch_size,
            ch_addralign,
        })
    )
);

impl Elf64_Chdr {
    fn to_le_bytes(&self)-> [u8; ELF64_CHDR_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend(&self.ch_type.to_le_bytes());
        ret_buffer.extend(&self.ch_reserved.to_le_bytes());
        ret_buffer.extend(&self.ch_size.to_le_bytes());
        ret_buffer.extend(&self.ch_addralign.to_le_bytes());
        return vec_to_array::<u8, ELF64_CHDR_SIZE>(ret_buffer);
    }
}


pub const ELF32_SYMBOL_SIZE: usize = 16;
pub const ELF64_SYMBOL_SIZE: usize = 24;
#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf32_Symbol {
    pub st_name: Elf32_Word	,
    pub st_value: Elf32_Addr	,
    pub st_size: Elf32_Word	,
    pub st_info: u8,
    pub st_other: u8,
    pub	st_shndx:Elf32_Half
}

named!(pub parser_elf32_symbol<Elf32_Symbol>,
    do_parse!(
        st_name:    le_u32    >>
        st_value:   le_u32    >>
        st_size:    le_u32    >>
        st_info:    le_u8    >>
        st_other:   le_u8    >>
        st_shndx:   le_u16    >>
        (Elf32_Symbol {
                st_name,
                st_value,
                st_size,
                st_info,
                st_other,
                st_shndx
        })
    )
);

impl Elf32_Symbol {
    fn to_le_bytes(&self)-> [u8; ELF32_SYMBOL_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.st_name.to_le_bytes());
        ret_buffer.extend_from_slice(&self.st_value.to_le_bytes());
        ret_buffer.extend_from_slice(&self.st_size.to_le_bytes());
        ret_buffer.extend_from_slice(&self.st_info.to_le_bytes());
        ret_buffer.extend_from_slice(&self.st_other.to_le_bytes());
        ret_buffer.extend_from_slice(&self.st_shndx.to_le_bytes());
        return vec_to_array::<u8, ELF32_SYMBOL_SIZE>(ret_buffer);
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf64_Symbol {
    pub	st_name: Elf64_Word,
    pub st_info: u8,
    pub st_other: u8,
    pub st_shndx: Elf64_Half	,
    pub st_value: Elf64_Addr	,
    pub st_size: Elf64_Xword	,
}

named!(pub parser_elf64_symbol<Elf64_Symbol>,
    do_parse!(
        st_name:    le_u32    >>
        st_info:    le_u8    >>
        st_shndx:   le_u16    >>
        st_other:   le_u8    >>
        st_value:   le_u64    >>
        st_size:    le_u64    >>
        (Elf64_Symbol {
            st_name,
            st_info,
            st_shndx,
            st_other,
            st_value,
            st_size,
        })
    )
);

impl Elf64_Symbol {
    fn to_le_bytes(&self)-> [u8; ELF64_SYMBOL_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.st_name.to_le_bytes());
        ret_buffer.extend_from_slice(&self.st_info.to_le_bytes());
        ret_buffer.extend_from_slice(&self.st_other.to_le_bytes());
        ret_buffer.extend_from_slice(&self.st_shndx.to_le_bytes());
        ret_buffer.extend_from_slice(&self.st_value.to_le_bytes());
        ret_buffer.extend_from_slice(&self.st_size.to_le_bytes());
        return vec_to_array::<u8, ELF64_SYMBOL_SIZE>(ret_buffer);
    }
}


pub const ELF32_RELOCATION_SIZE :usize = 8;
pub const ELF32_RELOCATIONA_SIZE :usize = 12;
pub const ELF64_RELOCATION_SIZE :usize = 16;
pub const ELF64_RELOCATIONA_SIZE :usize = 24;

#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf32_Relocation {
    pub r_offset: Elf32_Addr	,
    pub r_info: Elf32_Word	,
}

named!(pub parser_elf32_relocation<Elf32_Relocation>,
    do_parse!(
        r_offset:    le_u32    >>
        r_info:    le_u32    >>
        (Elf32_Relocation {
            r_offset,
            r_info,
        })
    )
);

impl Elf32_Relocation {
    fn to_le_bytes(&self)-> [u8; ELF32_RELOCATION_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.r_offset.to_le_bytes());
        ret_buffer.extend_from_slice(&self.r_info.to_le_bytes());
        return vec_to_array::<u8, ELF32_RELOCATION_SIZE>(ret_buffer);
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf32_RelocationA {
    pub r_offset:Elf32_Addr	,
    pub r_info:Elf32_Word	,
    pub r_addend:Elf32_Sword	,
}

named!(pub parser_elf32_relocationA<Elf32_RelocationA>,
    do_parse!(
        r_offset:    le_u32    >>
        r_info:    le_u32    >>
        r_addend:    le_i32    >>
        (Elf32_RelocationA {
            r_offset,
            r_info,
            r_addend,
        })
    )
);

impl Elf32_RelocationA {
    fn to_le_bytes(&self)-> [u8; ELF32_RELOCATIONA_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.r_offset.to_le_bytes());
        ret_buffer.extend_from_slice(&self.r_info.to_le_bytes());
        ret_buffer.extend_from_slice(&self.r_addend.to_le_bytes());
        return vec_to_array::<u8, ELF32_RELOCATIONA_SIZE>(ret_buffer);
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf64_Relocation {
    pub	r_offset:Elf64_Addr,
    pub	r_info:Elf64_Xword,
}

named!(pub parser_elf64_relocation<Elf64_Relocation>,
    do_parse!(
        r_offset:    le_u64    >>
        r_info:    le_u64    >>
        (Elf64_Relocation {
            r_offset,
            r_info,
        })
    )
);

impl Elf64_Relocation {
    fn to_le_bytes(&self)-> [u8; ELF64_RELOCATION_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.r_offset.to_le_bytes());
        ret_buffer.extend_from_slice(&self.r_info.to_le_bytes());
        return vec_to_array::<u8, ELF64_RELOCATION_SIZE>(ret_buffer);
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf64_RelocationA {
    pub r_offset:Elf64_Addr	,
    pub r_info:Elf64_Xword	,
    pub r_addend:Elf64_Sxword,
}

named!(pub parser_elf64_relocationA<Elf64_RelocationA>,
    do_parse!(
        r_offset:    le_u64    >>
        r_info:    le_u64    >>
        r_addend:    le_i64    >>
        (Elf64_RelocationA {
            r_offset,
            r_info,
            r_addend,
        })
    )
);

impl Elf64_RelocationA {
    fn to_le_bytes(&self)-> [u8; ELF64_RELOCATIONA_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.r_offset.to_le_bytes());
        ret_buffer.extend_from_slice(&self.r_info.to_le_bytes());
        ret_buffer.extend_from_slice(&self.r_addend.to_le_bytes());
        return vec_to_array::<u8, ELF64_RELOCATIONA_SIZE>(ret_buffer);
    }
}


pub const ELF32_DYNAMIC_SIZE :usize = 8;
pub const ELF64_DYNAMIC_SIZE :usize = 16;
#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf32_Dynamic {
    pub	d_tag: Elf32_Sword,
    pub	d_val: Elf32_Word,
}

named!(pub parser_elf32_dynamic<Elf32_Dynamic>,
    do_parse!(
        d_tag:    le_i32    >>
        d_val:    le_u32    >>
        (Elf32_Dynamic {
            d_tag,
            d_val,
        })
    )
);

impl Elf32_Dynamic {
    fn to_le_bytes(&self)-> [u8; ELF32_DYNAMIC_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.d_tag.to_le_bytes());
        ret_buffer.extend_from_slice(&self.d_val.to_le_bytes());
        return vec_to_array::<u8, ELF32_DYNAMIC_SIZE>(ret_buffer);
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf64_Dynamic {
    pub	d_tag: Elf64_Sxword,
    pub	d_val: Elf64_Xword,
}

named!(pub parser_elf64_dynamic<Elf64_Dynamic>,
    do_parse!(
        d_tag:    le_i64    >>
        d_val:    le_u64    >>
        (Elf64_Dynamic {
            d_tag,
            d_val,
        })
    )
);

impl Elf64_Dynamic {
    fn to_le_bytes(&self)-> [u8; ELF64_DYNAMIC_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend(&self.d_tag.to_le_bytes());
        ret_buffer.extend(&self.d_val.to_le_bytes());
        return vec_to_array::<u8, ELF64_DYNAMIC_SIZE>(ret_buffer);
    }
}


#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf32_Functor {
    pub func_address: Elf32_Addr
}

named!(pub parser_elf32_functor<Elf32_Functor>,
    do_parse!(
        func_address:    le_u32    >>
        (Elf32_Functor {
            func_address
        })
    )
);

impl From<Elf32_Addr> for Elf32_Functor {
    fn from(d_val: u32) -> Self {
        Elf32_Functor {
            func_address: d_val,
        }
    }
}

impl Elf32_Functor {
    fn to_le_bytes(&self)-> [u8; 4] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.func_address.to_le_bytes());
        return vec_to_array::<u8, 4>(ret_buffer);
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf64_Functor {
    pub func_address: Elf64_Addr
}

named!(pub parser_elf64_functor<Elf64_Functor>,
    do_parse!(
        func_address:    le_u64    >>
        (Elf64_Functor {
            func_address
        })
    )
);

impl Elf64_Functor {
    fn to_le_bytes(&self)-> [u8; 8] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.func_address.to_le_bytes());
        return vec_to_array::<u8, 8>(ret_buffer);
    }
}


pub const ELF32_VERDEF_SIZE :usize = 20;
pub const ELF64_VERDEF_SIZE :usize = 20;
#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf32_Verdef {
    pub vd_version: Elf32_Half,
    pub vd_flags: Elf32_Half,
    pub vd_ndx: Elf32_Half,
    pub vd_cnt: Elf32_Half,
    pub vd_hash: Elf32_Word,
    pub vd_aux: Elf32_Word,
    pub vd_next: Elf32_Word,
}
type Elf64_Verdef = Elf32_Verdef;

named!(pub parser_elf_verdef<Elf32_Verdef>,
    do_parse!(
        vd_version: le_u16    >>
        vd_flags:   le_u16    >>
        vd_ndx:     le_u16    >>
        vd_cnt:     le_u16    >>
        vd_hash:    le_u32    >>
        vd_aux:     le_u32    >>
        vd_next:    le_u32    >>
        (Elf32_Verdef {
            vd_version,
            vd_flags,
            vd_ndx,
            vd_cnt,
            vd_hash,
            vd_aux,
            vd_next,
        })
    )
);

// pub fn elf_verdef_to_bytes(verdef: &Elf32_Verdef) -> Vec<u8> {
//     let mut ret_buffer: Vec<u8> = Vec::new();
//     ret_buffer.extend(&verdef.vd_version.to_le_bytes());
//     ret_buffer.extend(&verdef.vd_flags.to_le_bytes());
//     ret_buffer.extend(&verdef.vd_ndx.to_le_bytes());
//     ret_buffer.extend(&verdef.vd_cnt.to_le_bytes());
//     ret_buffer.extend(&verdef.vd_hash.to_le_bytes());
//     ret_buffer.extend(&verdef.vd_aux.to_le_bytes());
//     ret_buffer.extend(&verdef.vd_next.to_le_bytes());
//     return ret_buffer;
// }

impl Elf32_Verdef {
    fn to_le_bytes(&self)-> [u8; ELF32_VERDEF_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.vd_version.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vd_flags.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vd_ndx.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vd_cnt.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vd_hash.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vd_aux.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vd_next.to_le_bytes());
        return vec_to_array::<u8, ELF32_VERDEF_SIZE>(ret_buffer);
    }
}



pub const ELF32_VERDAUX_SIZE :usize = 8;
#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf32_Verdaux {
    pub vda_name: Elf32_Word,
    pub vda_next: Elf32_Word,
}
type Elf64_Verdaux = Elf32_Verdaux;

named!(pub parser_elf_verdaux<Elf32_Verdaux>,
    do_parse!(
        vda_name: le_u32    >>
        vda_next: le_u32    >>
        (Elf32_Verdaux {
            vda_name,
            vda_next
        })
    )
);

impl Elf32_Verdaux {
    fn to_le_bytes(&self)-> [u8; ELF32_VERDAUX_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.vda_name.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vda_next.to_le_bytes());
        return vec_to_array::<u8, ELF32_VERDAUX_SIZE>(ret_buffer);
    }
}



pub const ELF32_VERNEED_SIZE :usize = 16;
#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf32_Verneed {
    pub vn_version: Elf32_Half,
    pub vn_cnt: Elf32_Half,
    pub vn_file: Elf32_Word,
    pub vn_aux: Elf32_Word,
    pub vn_next: Elf32_Word,
}
type Elf64_Verneed = Elf32_Verneed;

named!(pub parser_elf_verneed<Elf32_Verneed>,
    do_parse!(
        vn_version: le_u16    >>
        vn_cnt: le_u16    >>
        vn_file: le_u32    >>
        vn_aux: le_u32    >>
        vn_next: le_u32    >>
        (Elf32_Verneed {
            vn_version,
            vn_cnt,
            vn_file,
            vn_aux,
            vn_next,
        })
    )
);

impl Elf32_Verneed {
    fn to_le_bytes(&self)-> [u8; ELF32_VERNEED_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.vn_version.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vn_cnt.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vn_file.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vn_aux.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vn_next.to_le_bytes());
        return vec_to_array::<u8, ELF32_VERNEED_SIZE>(ret_buffer);
    }
}


pub const ELF32_VERAUX_SIZE :usize = 16;
#[derive(Copy, Clone, PartialEq, Eq, Default)]
pub struct Elf32_Vernaux {
    pub vna_hash: Elf32_Word,
    pub vna_flags: Elf32_Half,
    pub vna_other: Elf32_Half,
    pub vna_name: Elf32_Word,
    pub vna_next: Elf32_Word,
}
type Elf64_Vernaux = Elf32_Vernaux;

named!(pub parser_elf_veraux<Elf32_Vernaux>,
    do_parse!(
        vna_hash: le_u32    >>
        vna_flags: le_u16    >>
        vna_other: le_u16    >>
        vna_name: le_u32    >>
        vna_next: le_u32    >>
        (Elf32_Vernaux {
            vna_hash,
            vna_flags,
            vna_other,
            vna_name,
            vna_next,
        })
    )
);


impl Elf32_Vernaux {
    fn to_le_bytes(&self)-> [u8; ELF32_VERAUX_SIZE] {
        let mut ret_buffer: Vec<u8> = Vec::new();
        ret_buffer.extend_from_slice(&self.vna_hash.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vna_flags.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vna_other.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vna_name.to_le_bytes());
        ret_buffer.extend_from_slice(&self.vna_next.to_le_bytes());
        return vec_to_array::<u8, ELF32_VERAUX_SIZE>(ret_buffer);
    }
}

// pub fn elf_veraux_to_bytes(vernaux: &Elf32_Vernaux) -> Vec<u8> {
//     let mut ret_buffer: Vec<u8> = Vec::new();
//     ret_buffer.extend(&vernaux.vna_hash.to_le_bytes());
//     ret_buffer.extend(&vernaux.vna_flags.to_le_bytes());
//     ret_buffer.extend(&vernaux.vna_other.to_le_bytes());
//     ret_buffer.extend(&vernaux.vna_name.to_le_bytes());
//     ret_buffer.extend(&vernaux.vna_next.to_le_bytes());
//     return ret_buffer;
// }